#include "httpapi.h"
#include <string.h>

#include "esp_tls.h"
#include "esp_http_client.h"
#include "esp_log.h"
static const char *TAG = "HTTP_CLIENT";

static char *output_buffer;  // Buffer to store response of http request from event handler
static void(*respone)(char *data, void *user_data);
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    static int output_len;       // Stores number of bytes read
    switch (evt->event_id)
    {
        case HTTP_EVENT_ERROR:
            ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            //ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            if (strcmp(evt->header_key, "Location") == 0)
            {
                if (evt->user_data != NULL)
                {
                    int len = strlen(evt->header_value);
                    *(char **)evt->user_data = malloc(len + 1);
                    char *url = (char *)(*(char **)evt->user_data);
                    strcpy(url, evt->header_value);
                    url[len] = 0;
                }
            }
            break;
        case HTTP_EVENT_ON_DATA:
            //ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            /*
             *  Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
             *  However, event handler can also be used in case chunked encoding is used.
             */
            if (!esp_http_client_is_chunked_response(evt->client))
            {
                if (output_buffer == NULL)
                {
                    int len = esp_http_client_get_content_length(evt->client);
                    output_buffer = (char *) malloc(len + 1);
                    output_len = 0;

                    if (output_buffer == NULL)
                    {
                        ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
                        return ESP_FAIL;
                    }
                    output_buffer[len] = 0;
                }
                memcpy(output_buffer + output_len, evt->data, evt->data_len);
                output_len += evt->data_len;
            }

            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
            if (output_buffer != NULL)
            {
                // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
                // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
                if (respone)
                {
                    respone(output_buffer, evt->user_data);
                }
                free(output_buffer);
                output_buffer = NULL;
            }
            output_len = 0;
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            int mbedtls_err = 0;
            esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
            if (err != 0)
            {
                if (output_buffer != NULL)
                {
                    free(output_buffer);
                    output_buffer = NULL;
                }
                output_len = 0;
                ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
                ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
            }
            break;
    }
    return ESP_OK;
}


void http_rec_deal(esp_http_client_handle_t client, void(*func)(char *data, void *user_data))
{
    int len = esp_http_client_get_content_length(client);
    ESP_LOGI(TAG, "http need len %d", len);
    while (!esp_http_client_is_complete_data_received(client))
    {
        vTaskDelay(1 / portTICK_RATE_MS);
    };
    ESP_LOGW(TAG, "HTTP GET Status = %d, content_length = %d",
             esp_http_client_get_status_code(client), len);

}

int http_api_get(char *host, char *param, void(*func)(char *data, void *user_data), void *user_data)
{
    esp_err_t err = ESP_OK;
    ESP_LOGI(TAG,"http_api_get:%s%s", host,param);
    esp_http_client_config_t config =
    {
        .host = host,
        .path = param,
        .user_data = user_data,
        .transport_type = HTTP_TRANSPORT_OVER_TCP,
        .event_handler = _http_event_handler,
        .disable_auto_redirect = true,
        // .keep_alive_enable = false,
        .timeout_ms = 10000,
    };
    esp_http_client_handle_t client = 0;
    client = esp_http_client_init(&config);
    respone = func;
    // GET
    err = esp_http_client_perform(client);

    if (err == ESP_OK)
    {
        http_rec_deal(client, func);
    }
    else
    {
       esp_http_client_cleanup(client);
        ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
    }
    
    return err;

}
int http_api_post(char *host, char *param, void(*func)(char *data, void *user_data), void *user_data)
{
    ESP_LOGE(TAG, "http_api_get:%s", host);
    respone = func;
    esp_http_client_config_t config =
    {
        .host = host,
        .path = 0,
        .user_data = user_data,
        .transport_type = HTTP_TRANSPORT_OVER_TCP,
        .event_handler = _http_event_handler,
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);

    esp_http_client_set_method(client, HTTP_METHOD_POST);
    esp_http_client_set_post_field(client, param, strlen(param));
    esp_err_t err = esp_http_client_perform(client);
    if (err == ESP_OK)
    {
        http_rec_deal(client, func);
    }
    else
    {
        ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
    }
    return err;
}
